import 'dart:math';

import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter/rendering.dart';
import 'package:flutter/scheduler.dart';
import 'package:kq_flutter_core_widget/widgets/sliver/sliver_header.dart';

import 'link_scroll_controller.dart';

/// 表格控件
class KqTable extends StatefulWidget {
  /// 表格列数
  final int columnCount;

  /// 表格行数
  final int rowCount;

  /// 表格宽度
  final double? width;

  /// 表格高度
  final double? height;

  /// 单元格宽度测量器,返回单元格初始创建时的宽度，后续可能通过拖拽改变宽度。
  final CellWidthMeasureFactory cellWidthMeasure;

  /// 单元格高度测量器,返回单元格初始创建时的高度，后续可能通过拖拽改变高度。
  final CellHeightMeasureFactory cellHeightMeasure;

  /// 单元格更新时间，如果此时间与上次不一致，则表格完全重置。滑动的位置，拖拽改变的行高，列宽等置为初始值。
  /// 通过其它数据导致单元格的刷新，不会重置滑动的位置，拖拽改变的行高，列宽等
  final int updateTime;

  /// 单元格绘制器
  final CellRender cellRender;

  /// 顶部固定行数量，只能固定连续行，从第0行往下计算
  final int fixTopCount;

  /// 左边固定列数量，只能固定连续列，从第0列往右计算
  final int fixLeftCount;

  /// 右边固定列数量，只能固定连续列，从最后一列往左计算
  final int fixRightCount;

  /// 返回指定单元格拖拽改变行高/列宽的范围
  final CellBoxConstraintsFactory? cellBoxConstraints;

  /// 返回指定单元格是否可以拖拽改变列宽
  final CouldDragChangeWidthFactory? couldDragChangeWidth;

  /// 返回指定单元格是否可以拖拽改变行高
  final CouldDragChangeHeightFactory? couldDragChangeHeight;

  /// 是否一次性构建一列所有单元格宽度，然后使用最大宽度作为这一列宽度。
  /// 默认值为false，此时只会在界面已构建的所有(包括创建后滑出屏幕的单元格)单元格中去获取单元格的最大宽度作为列宽。
  final bool syncInitAllColumnWidth;

  /// 是否一次性构建一行所有单元格高度，然后使用最大高度作为这一行高度。
  /// 默认值为false，此时只会在界面已构建的所有(包括创建后滑出屏幕的单元格)单元格中去获取单元格的最大高度作为行高。
  final bool syncInitAllRowHeight;

  /// 表格控制器
  final TableController? tableController;

  /// 纵向滑动物理特性，主要是为了一些依赖[ScrollPhysics]实现上拉加载和下来刷新的框架
  final ScrollPhysics? verticalScrollPhysics;

  /// 表格顶部内容
  final List<Widget>? headers;

  /// 表格底部内容
  final List<Widget>? footers;

  /// 表格宽高变更时重置表格单元格大小，0：宽高变更均不重置，1：宽或高只要有一个变更即重置,2：仅宽度变更时重置，3：仅高度变更时重置
  final int sizeChangeResetCellSize;

  /// 高度根据内容自适应
  final bool shrinkWrap;

  const KqTable(
      {super.key,
      required this.columnCount,
      required this.rowCount,
      required this.cellWidthMeasure,
      required this.cellHeightMeasure,
      required this.cellRender,
      this.width,
      this.height,
      this.fixLeftCount = 0,
      this.fixRightCount = 0,
      this.fixTopCount = 0,
      this.updateTime = 0,
      this.cellBoxConstraints,
      this.couldDragChangeWidth,
      this.couldDragChangeHeight,
      this.syncInitAllColumnWidth = false,
      this.syncInitAllRowHeight = false,
      this.tableController,
      this.headers,
      this.footers,
      this.verticalScrollPhysics,
      this.sizeChangeResetCellSize = 0,
      this.shrinkWrap = false})
      : assert(fixLeftCount >= 0, "count must than or equal zero"),
        assert(fixRightCount >= 0, "count must than or equal zero"),
        assert(fixTopCount >= 0, "count must than or equal zero"),
        assert(
            sizeChangeResetCellSize == 0 ||
                sizeChangeResetCellSize == 1 ||
                sizeChangeResetCellSize == 2 ||
                sizeChangeResetCellSize == 3,
            "sizeChangeResetTableCellSize only set value 0，1，2 or 3"),
        assert(shrinkWrap == false || height == null,
            "vertical shrinkWrap, don't set height");

  @override
  State<StatefulWidget> createState() => TableState();
}

/// 处理表格相关逻辑
class TableState extends State<KqTable> {
  TableController? _tableController;

  /// 表格控制器
  TableController get tableController =>
      widget.tableController ?? (_tableController ??= TableController());

  ScrollPhysics? _verticalScrollPhysics;

  /// 纵向滑动物理特性
  ScrollPhysics get verticalScrollPhysics =>
      widget.verticalScrollPhysics ??
      (_verticalScrollPhysics ??= const ClampingScrollPhysics());

  // 记录每一列的列宽
  final Map<int, double> _mapWidth = {};

  // 记录每一列是否拖拽改变了宽度
  final Map<int, bool> _mapWidthDragChange = {};

  // 记录每一行的行高
  final Map<int, double> _mapHeight = {};

  // 记录每一行是否拖拽改变了行度
  final Map<int, bool> _mapHeightDragChange = {};

  // 当前是否触发了长按
  bool _isLongPress = false;

  // 长按时单元格的行坐标
  int _longPressRowIndex = -1;

  // 长按时单元格的列坐标
  int _longPressColumnIndex = -1;

  // 触发了长按的单元格的宽度
  double _longPressWidth = 0;

  // 触发了长按的单元格的高度
  double _longPressHeight = 0;

  /// 记录列表第一行控件对象
  final GlobalKey _tableTopRow = GlobalKey();

  /// 记录表格控件对象
  final GlobalKey _tableKey = GlobalKey();

  double? _oldWidth;
  double? _oldHeight;

  @override
  void initState() {
    super.initState();
    _oldWidth = widget.width;
    _oldWidth = widget.height;
    tableController._tableState = this;
    widget.cellRender._state = this;
  }

  @override
  void dispose() {
    super.dispose();
    widget.cellRender.disposeTable();
    tableController.dispose();
  }

  @override
  void didUpdateWidget(covariant KqTable oldWidget) {
    super.didUpdateWidget(oldWidget);
    tableController._tableState = this;
    widget.cellRender._state = this;
    if (oldWidget.updateTime != widget.updateTime) {
      _resetCellSize();
    }
  }

  _resetCellSize() {
    _mapWidth.clear();
    _mapWidthDragChange.clear();
    _mapHeight.clear();
    _mapHeightDragChange.clear();
  }

  @override
  Widget build(BuildContext context) {
    Widget result = LayoutBuilder(
      builder: (context, constraints) {
        var width = widget.width ?? constraints.maxWidth;
        var height = widget.height ?? constraints.maxHeight;
        _judgeResetCellSize(width, height);
        _oldWidth = width;
        _oldHeight = height;

        var decoration = widget.cellRender.buildBg();
        Widget result;
        if (decoration != null) {
          var padding = decoration.padding;
          if (widget.shrinkWrap) {
            result = _buildColumn(context, width, height);
          } else {
            width -= padding.horizontal;
            height -= padding.vertical;
            result = SizedBox(
              height: height,
              child: _buildColumn(context, width, height),
            );
          }

          result = Padding(padding: padding, child: result);
          result = DecoratedBox(decoration: decoration, child: result);
        } else if (widget.shrinkWrap) {
          result = _buildColumn(context, width, height);
        } else {
          result = SizedBox(
            height: height,
            child: _buildColumn(context, width, height),
          );
        }
        return result;
      },
    );

    result = ScrollConfiguration(
        behavior: const ScrollBehavior().copyWith(
          overscroll: false,
          scrollbars: false,
        ),
        child: result);
    return result;
  }

  _judgeResetCellSize(double width, double height) {
    if (widget.sizeChangeResetCellSize != 0) {
      var needClear = false;
      if (widget.sizeChangeResetCellSize == 2 && width != _oldWidth) {
        needClear = true;
      } else if (widget.sizeChangeResetCellSize == 3 && height != _oldHeight) {
        needClear = true;
      } else if (widget.sizeChangeResetCellSize == 1 &&
          (width != _oldWidth || height != _oldHeight)) {
        needClear = true;
      }

      if (needClear) {
        _resetCellSize();
      }
    }
  }

  /// 构建表格的纵向滑动列表，及上下固定行
  Widget _buildColumn(BuildContext context, double width, double height) {
    var sliverList = _CustomSliverFixedExtentList(
      tableState: this,
      axis: Axis.vertical,
      delegate: SliverChildBuilderDelegate(
        addAutomaticKeepAlives: false,
        addRepaintBoundaries: false,
        childCount: max(0, widget.rowCount - widget.fixTopCount),
        (context, index) =>
            _buildRow(context, index + widget.fixTopCount, width, false),
      ),
    );

    return CustomScrollView(
      key: _tableKey,
      shrinkWrap: widget.shrinkWrap,
      cacheExtent: widget.shrinkWrap ? null : height * 0.2,
      controller: tableController._buildColumnScrollController(0),
      physics: verticalScrollPhysics,
      slivers: [
        const SliverToBoxAdapter(
          child: SizedBox(
            width: 0,
            height: 0,
          ),
        ),
        // 表格行第一个必须加一个非固定的内容，否则如果physics设置为BouncingScrollPhysics这种类型时，顶部固定的内容不会下移
        if (widget.headers != null && widget.headers!.isNotEmpty)
          ...widget.headers!,
        for (int i = 0; i < min(widget.fixTopCount, widget.rowCount); i++)
          _buildRow(context, i, width, true),
        sliverList,
        if (widget.footers != null && widget.footers!.isNotEmpty)
          ...widget.footers!,
      ],
    );
  }

  /// 构建表格行
  Widget _buildRow(BuildContext context, int row, double width, bool pinned) {
    ScrollController scrollController =
        tableController._buildRowScrollController(row);
    if (widget.syncInitAllRowHeight) {
      if (_mapHeightDragChange[row] != true) {
        double maxHeight = 0;
        for (int i = 0; i < widget.columnCount; i++) {
          var height = _getCellHeight(row, i);
          if (maxHeight < height) {
            maxHeight = height;
          }
        }
        _mapHeight[row] = maxHeight;
      }
    } else {
      _mapHeight.putIfAbsent(row, () => _getCellHeight(row, 0));
    }

    var rowChild = SizedBox(
      key: row == 0 ? _tableTopRow : null,
      height: _mapHeight[row]!,
      width: width,
      child: Row(
        children: _buildRowCell(context, width, scrollController, row),
      ),
    );

    if (pinned) {
      return SliverHeader.builder(
          pinned: true,
          childBuilder: (context, shrinkOffset, overlapsContent) => rowChild);
    }

    return rowChild;
  }

  /// 构建表格每行的单元格及左右固定单元格
  List<Widget> _buildRowCell(BuildContext context, double width,
      ScrollController scrollController, int row) {
    var children = <Widget>[];
    if (widget.fixLeftCount > 0) {
      for (int i = 0; i < min(widget.fixLeftCount, widget.columnCount); i++) {
        children.add(_buildGestureCell(context, row, i));
      }
    }

    var fixTotalCount = widget.fixLeftCount + widget.fixRightCount;
    if (fixTotalCount < widget.columnCount) {
      var list = Expanded(
        child: CustomScrollView(
          cacheExtent: width * 0.2,
          controller: scrollController,
          physics: const ClampingScrollPhysics(),
          scrollDirection: Axis.horizontal,
          slivers: [
            _CustomSliverFixedExtentList(
              tableState: this,
              axis: Axis.horizontal,
              delegate: SliverChildBuilderDelegate(
                addAutomaticKeepAlives: false,
                addRepaintBoundaries: false,
                childCount: max(0, widget.columnCount - fixTotalCount),
                (context, index) => _buildGestureCell(
                    context, row, index + widget.fixLeftCount),
              ),
            ),
          ],
        ),
      );
      children.add(list);
    }

    int fixRightCount;
    if (fixTotalCount <= widget.columnCount) {
      fixRightCount = widget.fixRightCount;
    } else if (widget.fixLeftCount >= widget.columnCount) {
      fixRightCount = 0;
    } else {
      fixRightCount = widget.columnCount - widget.fixLeftCount;
    }

    if (fixRightCount > 0) {
      for (int i = fixRightCount; i >= 1; i--) {
        children.add(_buildGestureCell(context, row, widget.columnCount - i));
      }
    }

    return children;
  }

  /// 构建带手势的单元格，处理拖拽改变行高和列宽的功能
  Widget _buildGestureCell(BuildContext context, int row, int column) {
    var couldDragChangeWidth =
        widget.couldDragChangeWidth?.call(row, column) == true;
    var couldDragChangeHeight =
        widget.couldDragChangeHeight?.call(row, column) == true;
    bool couldDetect = couldDragChangeWidth || couldDragChangeHeight;
    return GestureDetector(
      onLongPress: couldDetect ? () => _onLongPress(row, column) : null,
      onLongPressMoveUpdate: couldDetect
          ? (details) => _onLongPressMoveUpdate(row, column, details)
          : null,
      onLongPressEnd:
          couldDetect ? (details) => _onLongPressEnd(row, column) : null,
      onLongPressCancel:
          couldDetect ? () => _onLongPressEnd(row, column) : null,
      child: _buildCell(context, row, column, couldDetect),
    );
  }

  /// 单元格被长按
  void _onLongPress(int row, int column) {
    setState(() {
      _isLongPress = true;
      _longPressColumnIndex = column;
      _longPressRowIndex = row;
      _longPressWidth = _mapWidth[column] ?? _getCellWidth(row, column);
      _longPressHeight = _mapHeight[row] ?? _getCellHeight(row, column);
    });
  }

  /// 单元格长按后滑动事件
  void _onLongPressMoveUpdate(
      int row, int column, LongPressMoveUpdateDetails details) {
    if (!_isLongPress) {
      return;
    }

    double? oldWidth = _mapWidth[column];
    double? oldHeight = _mapHeight[row];
    bool needUpdate = false;
    BoxConstraints? boxConstraints;

    bool dragRow = details.localOffsetFromOrigin.dy.abs() > 0 &&
        widget.couldDragChangeHeight?.call(row, column) == true;
    bool drawColumn = details.localOffsetFromOrigin.dx.abs() > 0 &&
        widget.couldDragChangeWidth?.call(row, column) == true;
    if (dragRow && drawColumn) {
      boxConstraints = widget.cellBoxConstraints?.call(row, column);
    }

    if (drawColumn) {
      _mapWidthDragChange[column] = true;
      var value = _longPressWidth + details.localOffsetFromOrigin.dx;
      boxConstraints =
          boxConstraints ?? widget.cellBoxConstraints?.call(row, column);
      value = _mapSize(boxConstraints, value, isWidth: true);
      if (oldWidth == null || oldWidth != value) {
        _mapWidth[column] = value;
        needUpdate = true;
      }
    }

    if (dragRow) {
      _mapHeightDragChange[row] = true;
      var value = _longPressHeight + details.localOffsetFromOrigin.dy;
      boxConstraints =
          boxConstraints ?? widget.cellBoxConstraints?.call(row, column);
      value = _mapSize(boxConstraints, value, isWidth: false);
      if (oldHeight == null || oldHeight != value) {
        _mapHeight[row] = value;
        needUpdate = true;
      }
    }

    if (needUpdate) {
      setState(() {});
    }
  }

  /// 长按事件结束
  void _onLongPressEnd(int row, int column) {
    if (!_isLongPress) {
      return;
    }

    setState(() {
      _isLongPress = false;
      _longPressColumnIndex = -1;
      _longPressRowIndex = -1;
      _longPressWidth = 0;
      _longPressHeight = 0;
    });
  }

  /// 是否需要重置整行的高或整列的宽
  bool _needResetSize = false;

  /// 构建每一个具体的单元格
  Widget? _buildCell(
      BuildContext context, int row, int column, bool disposeGesture) {
    var columnDragChange = _mapWidthDragChange[column];
    var rowDragChange = _mapHeightDragChange[row];

    if (widget.syncInitAllColumnWidth &&
        columnDragChange != true &&
        _mapWidth[column] == null) {
      // 当前列没有拖拽改变列宽且第一次创建
      double maxWidth = 0;
      for (int i = 0; i < widget.rowCount; i++) {
        var width = _getCellWidth(i, column);
        if (maxWidth < width) {
          maxWidth = width;
        }
      }
      _mapWidth[column] = maxWidth;
    }

    var measureWidth = widget.syncInitAllColumnWidth || columnDragChange == true
        ? _mapWidth[column] ?? _getCellWidth(row, column)
        : _getCellWidth(row, column);
    var measureHeight = widget.syncInitAllRowHeight || rowDragChange == true
        ? _mapHeight[row] ?? _getCellHeight(row, column)
        : _getCellHeight(row, column);

    double width = _mapWidth.putIfAbsent(column, () => measureWidth);
    double height = _mapHeight.putIfAbsent(row, () => measureHeight);
    bool needUpdate2 = false;
    if (width < measureWidth || height < measureHeight) {
      if (width < measureWidth) {
        _mapWidth[column] = measureWidth;
      }

      if (height < measureHeight) {
        _mapHeight[row] = measureHeight;
      }

      width = measureWidth;
      height = measureHeight;
      needUpdate2 = true;
    }

    if (needUpdate2 && !_needResetSize) {
      _needResetSize = true;
      SchedulerBinding.instance.addPostFrameCallback((timeStamp) {
        setState(() {
          _needResetSize = false;
        });
      });
    }

    if (disposeGesture && widget.cellRender._handler == null) {
      widget.cellRender._handler = GestureLongPressHandler(this);
    }

    return widget.cellRender.build(context, row, column, width, height,
        column == _longPressColumnIndex && row == _longPressRowIndex);
  }

  /// 更新表格
  _update(VoidCallback callback) {
    setState(callback);
  }

  double _getCellWidth(int row, int column) {
    var value = widget.cellWidthMeasure.call(row, column);
    var constraints = widget.cellBoxConstraints?.call(row, column);
    return _mapSize(constraints, value, isWidth: true);
  }

  double _getCellHeight(int row, int column) {
    var value = widget.cellHeightMeasure.call(row, column);
    var constraints = widget.cellBoxConstraints?.call(row, column);
    return _mapSize(constraints, value, isWidth: false);
  }

  /// 将给定值限制在[constraints]范围内
  double _mapSize(BoxConstraints? constraints, double value,
      {required bool isWidth}) {
    if (constraints == null) {
      return value;
    }

    double minValue = isWidth ? constraints.minWidth : constraints.minHeight;
    double maxValue = isWidth ? constraints.maxWidth : constraints.maxWidth;

    if (minValue == double.infinity ||
        maxValue == double.infinity ||
        minValue <= maxValue) {
      if (minValue != double.infinity && value < minValue) {
        return minValue;
      }

      if (maxValue != double.infinity && value > maxValue) {
        return maxValue;
      }
    }

    return max(0, value);
  }

  /// 表格第一行在表格中的坐标
  double get tableFirstRowTop {
    var renderObject = _tableTopRow.currentContext?.findRenderObject();
    if (renderObject is! RenderBox) {
      return 0;
    }

    var renderObject2 = _tableKey.currentContext?.findRenderObject();
    if (renderObject2 is! RenderBox) {
      return 0;
    }

    return renderObject.localToGlobal(Offset.zero, ancestor: renderObject2).dy;
  }
}

/// 处理长按相关手势
///
/// 当表格的单元格拦截[GestureLongPressHandler]中定义的相关事件时，
/// 如果希望[KqTable]还能处理拖拽改变行高和列宽，则需要外部调用此类相关方法
class GestureLongPressHandler {
  final TableState _state;

  const GestureLongPressHandler(this._state);

  /// 长按手势触发
  void onLongPress(int row, int column) {
    _state._onLongPress(row, column);
  }

  /// 长按后滑动事件触发
  void onLongPressMoveUpdate(
      int row, int column, LongPressMoveUpdateDetails details) {
    _state._onLongPressMoveUpdate(row, column, details);
  }

  /// 长按事件结束
  void onLongPressEnd(int row, int column, LongPressEndDetails details) {
    _state._onLongPressEnd(row, column);
  }

  /// 长按事件被取消
  void onLongPressCancel(int row, int column) {
    _state._onLongPressEnd(row, column);
  }
}

/// 自定义固定高度/宽度列表
///
/// 不需要每行/每列高度一致，会根据当前滑动距离，通过高度/宽度计算方法得出表格需要显示的内容。
/// 而不是像SliverList一样对滑动位置之前的所有Widget执行一遍build，从而再得到尺寸数据
class _CustomSliverFixedExtentList extends SliverMultiBoxAdaptorWidget {
  final TableState tableState;
  final Axis axis;

  const _CustomSliverFixedExtentList(
      {required super.delegate, required this.tableState, required this.axis});

  @override
  RenderSliverMultiBoxAdaptor createRenderObject(BuildContext context) {
    final SliverMultiBoxAdaptorElement element =
        context as SliverMultiBoxAdaptorElement;
    return _CustomRenderSliverFixedExtentList(
        childManager: element, tableState: tableState, scrollDirection: axis);
  }
}

// 基于[RenderSliverFixedExtentBoxAdaptor]进行修改
class _CustomRenderSliverFixedExtentList extends RenderSliverMultiBoxAdaptor {
  final TableState tableState;
  final Axis scrollDirection;

  _CustomRenderSliverFixedExtentList(
      {required super.childManager,
      required this.tableState,
      required this.scrollDirection});

  int _mapIndex(int index) {
    if (scrollDirection == Axis.vertical) {
      return tableState.widget.fixTopCount + index;
    } else {
      return tableState.widget.fixLeftCount + index;
    }
  }

  /// 获取每个单元格在滑动方向上的尺寸
  double getItemExtent(int index) {
    var mapIndex = _mapIndex(index);
    if (scrollDirection == Axis.vertical) {
      return tableState._mapHeight
          .putIfAbsent(mapIndex, () => tableState._getCellHeight(mapIndex, 0));
    }

    return tableState._mapWidth
        .putIfAbsent(mapIndex, () => tableState._getCellWidth(0, mapIndex));
  }

  /// 获取[from]下标到[to]下标数据总距离，不包含[to]下标
  double getItemRangeExtent(int from, int to) {
    double offset = 0;
    for (int i = from; i < to; i++) {
      offset += getItemExtent(i);
    }
    return offset;
  }

  /// 获取指定下标距离起始位置的距离
  double indexToLayoutOffset(int index) {
    return getItemRangeExtent(0, index);
  }

  /// 获取偏移[scrollOffset]后界面显示的组件坐标，[isMax]为true表示取超过scrollOffset后的第一个child坐标
  int _getChildIndexForScrollOffset(double scrollOffset, bool isMax) {
    int index = 0;
    double itemExtent = getItemExtent(index);
    while (itemExtent < scrollOffset) {
      index++;
      itemExtent += getItemExtent(index);
    }

    return isMax ? index : max(0, index - 1);
  }

  /// 获取偏移[scrollOffset]处左边第一个child下标
  int getMinChildIndexForScrollOffset(double scrollOffset) {
    return _getChildIndexForScrollOffset(scrollOffset, false);
  }

  /// 获取偏移[scrollOffset]处右边第一个child下标
  int getMaxChildIndexForScrollOffset(double scrollOffset) {
    return _getChildIndexForScrollOffset(scrollOffset, true);
  }

  double estimateMaxScrollOffset(
    SliverConstraints constraints, {
    int? firstIndex,
    int? lastIndex,
    double? leadingScrollOffset,
    double? trailingScrollOffset,
  }) {
    return childManager.estimateMaxScrollOffset(
      constraints,
      firstIndex: firstIndex,
      lastIndex: lastIndex,
      leadingScrollOffset: leadingScrollOffset,
      trailingScrollOffset: trailingScrollOffset,
    );
  }

  /// 计算最大可滑动距离
  double computeMaxScrollOffset(SliverConstraints constraints) {
    return getItemRangeExtent(0, childManager.childCount);
  }

  int _calculateLeadingGarbage(int firstIndex) {
    RenderBox? walker = firstChild;
    int leadingGarbage = 0;
    while (walker != null && indexOf(walker) < firstIndex) {
      leadingGarbage += 1;
      walker = childAfter(walker);
    }
    return leadingGarbage;
  }

  int _calculateTrailingGarbage(int targetLastIndex) {
    RenderBox? walker = lastChild;
    int trailingGarbage = 0;
    while (walker != null && indexOf(walker) > targetLastIndex) {
      trailingGarbage += 1;
      walker = childBefore(walker);
    }
    return trailingGarbage;
  }

  @override
  void performLayout() {
    final SliverConstraints constraints = this.constraints;
    childManager.didStartLayout();
    childManager.setDidUnderflow(false);

    final double scrollOffset =
        constraints.scrollOffset + constraints.cacheOrigin;
    assert(scrollOffset >= 0.0);
    final double remainingExtent = constraints.remainingCacheExtent;
    assert(remainingExtent >= 0.0);
    final double targetEndScrollOffset = scrollOffset + remainingExtent;

    final BoxConstraints childConstraints = constraints.asBoxConstraints();

    final int firstIndex = getMinChildIndexForScrollOffset(scrollOffset);
    final int? targetLastIndex = targetEndScrollOffset.isFinite
        ? getMaxChildIndexForScrollOffset(targetEndScrollOffset)
        : null;

    if (firstChild != null) {
      final int leadingGarbage = _calculateLeadingGarbage(firstIndex);
      final int trailingGarbage = targetLastIndex != null
          ? _calculateTrailingGarbage(targetLastIndex)
          : 0;
      collectGarbage(leadingGarbage, trailingGarbage);
    } else {
      collectGarbage(0, 0);
    }

    if (firstChild == null) {
      if (!addInitialChild(
          index: firstIndex, layoutOffset: indexToLayoutOffset(firstIndex))) {
        // There are either no children, or we are past the end of all our children.
        final double max;
        if (firstIndex <= 0) {
          max = 0.0;
        } else {
          max = computeMaxScrollOffset(constraints);
        }
        geometry = SliverGeometry(
          scrollExtent: max,
          maxPaintExtent: max,
        );
        childManager.didFinishLayout();
        return;
      }
    }

    RenderBox? trailingChildWithLayout;

    for (int index = indexOf(firstChild!) - 1; index >= firstIndex; --index) {
      final RenderBox? child =
          insertAndLayoutLeadingChild(childConstraints, parentUsesSize: true);
      if (child == null) {
        // Items before the previously first child are no longer present.
        // Reset the scroll offset to offset all items prior and up to the
        // missing item. Let parent re-layout everything.
        geometry = SliverGeometry(
            scrollOffsetCorrection: getItemRangeExtent(0, index));
        return;
      }
      final SliverMultiBoxAdaptorParentData childParentData =
          child.parentData! as SliverMultiBoxAdaptorParentData;
      childParentData.layoutOffset = indexToLayoutOffset(index);
      assert(childParentData.index == index);
      trailingChildWithLayout ??= child;
    }

    if (trailingChildWithLayout == null) {
      firstChild!.layout(childConstraints, parentUsesSize: true);
      final SliverMultiBoxAdaptorParentData childParentData =
          firstChild!.parentData! as SliverMultiBoxAdaptorParentData;
      childParentData.layoutOffset = indexToLayoutOffset(firstIndex);
      trailingChildWithLayout = firstChild;
    }

    double estimatedMaxScrollOffset = double.infinity;
    for (int index = indexOf(trailingChildWithLayout!) + 1;
        targetLastIndex == null || index <= targetLastIndex;
        ++index) {
      RenderBox? child = childAfter(trailingChildWithLayout!);
      if (child == null || indexOf(child) != index) {
        child = insertAndLayoutChild(childConstraints,
            after: trailingChildWithLayout, parentUsesSize: true);
        if (child == null) {
          // We have run out of children.
          estimatedMaxScrollOffset = getItemRangeExtent(0, index);
          break;
        }
      } else {
        child.layout(childConstraints, parentUsesSize: true);
      }
      trailingChildWithLayout = child;
      final SliverMultiBoxAdaptorParentData childParentData =
          child.parentData! as SliverMultiBoxAdaptorParentData;
      assert(childParentData.index == index);
      childParentData.layoutOffset =
          indexToLayoutOffset(childParentData.index!);
    }

    final int lastIndex = indexOf(lastChild!);
    final double leadingScrollOffset = indexToLayoutOffset(firstIndex);
    final double trailingScrollOffset = indexToLayoutOffset(lastIndex + 1);

    assert(firstIndex == 0 ||
        childScrollOffset(firstChild!)! - scrollOffset <=
            precisionErrorTolerance);
    assert(debugAssertChildListIsNonEmptyAndContiguous());
    assert(indexOf(firstChild!) == firstIndex);
    assert(targetLastIndex == null || lastIndex <= targetLastIndex);

    estimatedMaxScrollOffset = min(
      estimatedMaxScrollOffset,
      estimateMaxScrollOffset(
        constraints,
        firstIndex: firstIndex,
        lastIndex: lastIndex,
        leadingScrollOffset: leadingScrollOffset,
        trailingScrollOffset: trailingScrollOffset,
      ),
    );

    final double paintExtent = calculatePaintOffset(
      constraints,
      from: leadingScrollOffset,
      to: trailingScrollOffset,
    );

    final double cacheExtent = calculateCacheOffset(
      constraints,
      from: leadingScrollOffset,
      to: trailingScrollOffset,
    );

    final double targetEndScrollOffsetForPaint =
        constraints.scrollOffset + constraints.remainingPaintExtent;
    final int? targetLastIndexForPaint = targetEndScrollOffsetForPaint.isFinite
        ? getMaxChildIndexForScrollOffset(targetEndScrollOffsetForPaint)
        : null;
    geometry = SliverGeometry(
      scrollExtent: estimatedMaxScrollOffset,
      paintExtent: paintExtent,
      cacheExtent: cacheExtent,
      maxPaintExtent: estimatedMaxScrollOffset,
      // Conservative to avoid flickering away the clip during scroll.
      hasVisualOverflow: (targetLastIndexForPaint != null &&
              lastIndex >= targetLastIndexForPaint) ||
          constraints.scrollOffset > 0.0,
    );

    // We may have started the layout while scrolled to the end, which would not
    // expose a new child.
    if (estimatedMaxScrollOffset == trailingScrollOffset) {
      childManager.setDidUnderflow(true);
    }
    childManager.didFinishLayout();
  }
}

/// 单元格数据
class CellData {
  /// 单元格所在行
  final int row;

  /// 单元格所在列
  final int column;

  /// 单元格宽度，此宽度为实际绘制的宽度，绘制前赋值
  final double width;

  /// 单元格高度，此高度为实际绘制的高度，绘制前赋值
  final double height;

  /// 当前单元格是否出发了长按
  final bool isLongPress;

  const CellData(
      this.row, this.column, this.width, this.height, this.isLongPress);
}

/// 单元格绘制器
abstract class CellRender {
  TableState? _state;
  GestureLongPressHandler? _handler;

  /// 构建单元格组件
  ///
  /// [isLongPress]表示单元格此时是否触发了长按。当此单元格拦截了[GestureLongPressHandler]定义的相关事件时，
  /// 如果希望[KqTable]还能处理拖拽改变行高和列宽，则需要外部获取[gestureLongPressHandler]调用相关事件方法。
  Widget build(BuildContext context, int row, int column, double width,
      double height, bool isLongPress);

  /// 构建表格背景装饰
  Decoration? buildBg() {
    return null;
  }

  /// 获取单元格所在的表格，当[KqTable]build后才有值
  KqTable? get table => _state?.widget;

  /// 处理长按相关手势
  GestureLongPressHandler? get gestureLongPressHandler => _handler;

  /// 刷新表格
  void updateTable(VoidCallback callback) {
    _state?._update(callback);
  }

  /// 表格销毁时调用
  void disposeTable() {
    _state = null;
    _handler = null;
  }
}

/// 单元格控制器
class TableController {
  /// 纵向滚动控制器
  final LinkedScrollControllerGroup _verticalScrollController =
      LinkedScrollControllerGroup();

  /// 横向滚动控制器
  final LinkedScrollControllerGroup _horizontalScrollController =
      LinkedScrollControllerGroup();

  /// 记录纵向滑动控制器，表格每列数据有一个纵向控制器，此列表为了同步所有纵向控制器相关操作。当滑动的主轴是纵向时，只创建第一列控制器。
  final Map<int, ScrollController> _verticalScrollControllers = {};

  /// 记录横向滑动控制器，表格每行数据有一个横向控制器，此列表为了同步所有横向控制器相关操作。当滑动的主轴是横向时，只创建第一行控制器。
  final Map<int, ScrollController> _horizontalScrollControllers = {};

  TableState? _tableState;

  /// 纵向滑动到指定位置
  Future<void> animateVerticalTo(
    double offset, {
    required Curve curve,
    required Duration duration,
  }) async {
    return _verticalScrollController.animateTo(offset,
        curve: curve, duration: duration);
  }

  /// 纵向滑动到指定位置
  void jumpVerticalTo(double value) {
    _verticalScrollController.jumpTo(value);
  }

  /// 横向滑动到指定位置
  Future<void> animateHorizontalTo(
    double offset, {
    required Curve curve,
    required Duration duration,
  }) async {
    return _horizontalScrollController.animateTo(offset,
        curve: curve, duration: duration);
  }

  /// 横向滑动到指定位置
  void jumpHorizontalTo(double value) {
    _horizontalScrollController.jumpTo(value);
  }

  /// 获取滑动到指定行或列需要滚动的距离
  double? _getToRowOrColumnOffset(int endIndex, bool isVertical) {
    var state = _tableState;
    if (state == null) {
      return null;
    }

    var totalSize =
        isVertical ? state.widget.rowCount : state.widget.columnCount;
    if (endIndex < 0 || endIndex >= totalSize) {
      return null;
    }

    double offset = 0;
    for (int i = 0; i < endIndex; i++) {
      offset += isVertical
          ? state._mapHeight.putIfAbsent(i, () => state._getCellHeight(i, 0))
          : state._mapWidth.putIfAbsent(i, () => state._getCellWidth(0, i));
    }

    if (isVertical) {
      return offset - state.tableFirstRowTop;
    }
    return offset;
  }

  /// 滑动到指定行
  ///
  /// 如果[row]不在表格行数范围内则不执行
  void jumpToRow(int row) {
    var offset = _getToRowOrColumnOffset(row, true);
    if (offset == null) {
      return;
    }
    jumpVerticalTo(offset);
  }

  /// 滑动到指定列
  ///
  /// 如果[column]不在表格列数范围内则不执行
  void jumpToColumn(int column) {
    var offset = _getToRowOrColumnOffset(column, false);
    if (offset == null) {
      return;
    }
    jumpHorizontalTo(offset);
  }

  /// 滑动到指定行
  ///
  /// 如果[row]不在表格行数范围内则不执行
  Future<void>? animateToRow(
    int row, {
    required Curve curve,
    required Duration duration,
  }) {
    var offset = _getToRowOrColumnOffset(row, true);
    if (offset == null) {
      return null;
    }
    return animateVerticalTo(offset, curve: curve, duration: duration);
  }

  /// 滑动到指定列
  ///
  /// 如果[column]不在表格列数范围内则不执行
  Future<void>? animateToColumn(
    int column, {
    required Curve curve,
    required Duration duration,
  }) {
    var offset = _getToRowOrColumnOffset(column, false);
    if (offset == null) {
      return null;
    }
    return animateHorizontalTo(offset, curve: curve, duration: duration);
  }

  /// 滑动到指定行和列
  ///
  /// 如果[row]不在表格行数范围内则纵向滑动不执行
  /// 如果[column]不在表格列数范围内则横向滑动不执行
  void jumpTo(int row, int column) {
    jumpToRow(row);
    jumpToColumn(column);
  }

  /// 滑动到指定行和列
  ///
  /// 如果[row]不在表格行数范围内则纵向滑动不执行
  /// 如果[column]不在表格列数范围内则横向滑动不执行
  Future<void>? animateTo(int row, int column,
      {required Curve curve, required Duration duration}) {
    var offset = _getToRowOrColumnOffset(row, true);
    var offsetColumn = _getToRowOrColumnOffset(column, false);
    if (offset != null && offsetColumn != null) {
      var futures = [
        animateVerticalTo(offset, curve: curve, duration: duration),
        animateHorizontalTo(offsetColumn, curve: curve, duration: duration)
      ];
      return Future.any(futures);
    } else if (offset != null) {
      return animateVerticalTo(offset, curve: curve, duration: duration);
    } else if (offsetColumn != null) {
      return animateHorizontalTo(offsetColumn,
          curve: curve, duration: duration);
    }
    return null;
  }

  /// 横向和纵向滑动到指定位置
  void jumpBothTo(double verticalOffset, double horizontalOffset) {
    jumpVerticalTo(verticalOffset);
    jumpHorizontalTo(horizontalOffset);
  }

  /// 横向和纵向滑动到指定位置
  Future<void> animateBothTo(double verticalOffset, double horizontalOffset,
      {required Curve curve, required Duration duration}) {
    var futures = [
      animateVerticalTo(verticalOffset, curve: curve, duration: duration),
      animateHorizontalTo(horizontalOffset, curve: curve, duration: duration)
    ];
    return Future.any(futures);
  }

  /// 构建行滚动控制器
  ScrollController _buildRowScrollController(int row) {
    return _horizontalScrollController.addAndGet(row);
  }

  /// 构建列滚动控制器
  ScrollController _buildColumnScrollController(int column) {
    return _verticalScrollController.addAndGet(column);
  }

  void dispose() {
    _tableState = null;
    _verticalScrollController.dispose();
    _horizontalScrollController.dispose();
    _verticalScrollControllers.clear();
    _horizontalScrollControllers.clear();
  }

  /// 添加纵向滑动监听
  void addVerticalOffsetChangedListener(VoidCallback onChanged) {
    _verticalScrollController.addOffsetChangedListener(onChanged);
  }

  /// 移除纵向滑动监听
  void removeVerticalOffsetChangedListener(VoidCallback listener) {
    _verticalScrollController.removeOffsetChangedListener(listener);
  }

  /// 添加水平方向滑动监听
  void addHorizontalOffsetChangedListener(VoidCallback onChanged) {
    _horizontalScrollController.addOffsetChangedListener(onChanged);
  }

  /// 移除水平方向滑动监听
  void removeHorizontalOffsetChangedListener(VoidCallback listener) {
    _horizontalScrollController.removeOffsetChangedListener(listener);
  }

  /// 添加纵向和水平方向滑动监听
  void addOffsetChangedListener(VoidCallback onChanged) {
    _verticalScrollController.addOffsetChangedListener(onChanged);
    _horizontalScrollController.addOffsetChangedListener(onChanged);
  }

  /// 移除纵向和水平方向滑动监听
  void removeOffsetChangedListener(VoidCallback onChanged) {
    _verticalScrollController.removeOffsetChangedListener(onChanged);
    _horizontalScrollController.removeOffsetChangedListener(onChanged);
  }

  /// The current scroll offset of the group.
  double get verticalOffset {
    return _verticalScrollController.offset;
  }

  /// Returns the attached [ScrollPosition], from which the actual scroll offset
  /// of the [ScrollView] can be obtained.
  ///
  /// Calling this is only valid when only a single position is attached.
  ScrollPosition get verticalPosition {
    return _verticalScrollController.position;
  }

  /// The current scroll offset of the group.
  double get horizontalOffset {
    return _horizontalScrollController.offset;
  }

  /// Returns the attached [ScrollPosition], from which the actual scroll offset
  /// of the [ScrollView] can be obtained.
  ///
  /// Calling this is only valid when only a single position is attached.
  ScrollPosition get horizontalPosition {
    return _horizontalScrollController.position;
  }

  /// 获取指定单元格尺寸值，此数值非精确数值，如果想获取精确数值，请确保表格绘制完成
  Size? getCellSize(int row, int column) {
    var state = _tableState;
    if (state == null) {
      return null;
    }
    var width = state._mapWidth[column];
    var height = state._mapHeight[row];
    return width == null || height == null ? null : Size(width, height);
  }

  /// 获取指定列宽度，此数值非精确数值，如果想获取精确数值，请确保表格绘制完成
  double? getCellWidth(int column) {
    var state = _tableState;
    if (state == null) {
      return null;
    }
    return state._mapWidth[column];
  }

  /// 获取指定行高度，此数值非精确数值，如果想获取精确数值，请确保表格绘制完成
  double? getCellHeight(int row) {
    var state = _tableState;
    if (state == null) {
      return null;
    }
    return state._mapWidth[row];
  }
}

/// 测量单元格的宽
typedef CellWidthMeasureFactory = double Function(int row, int column);

/// 测量单元格的高
typedef CellHeightMeasureFactory = double Function(int row, int column);

/// 指定单元格的尺寸范围
typedef CellBoxConstraintsFactory = BoxConstraints Function(
    int row, int column);

/// 是否可以拖拽改变行高
typedef CouldDragChangeWidthFactory = bool Function(int row, int column);

/// 是否可以拖拽改变列宽
typedef CouldDragChangeHeightFactory = bool Function(int row, int column);

/// 刷新表格器
typedef Updater = void Function();
